package com.beiben.work.process.service.impl;


import com.beiben.common.GlobalConstant;
import com.beiben.project.domain.Project;
import com.beiben.project.mapper.ProjectMapper;
import com.beiben.system.file.domain.File;
import com.beiben.system.file.service.IFileService;
import com.beiben.system.user.domain.BeiBenUser;
import com.beiben.system.user.service.IBeiBenUserService;
import com.beiben.utils.DateUtil;
import com.beiben.utils.SortComparator;
import com.beiben.work.process.domain.FileProcess;
import com.beiben.work.process.domain.FileProcessUser;
import com.beiben.work.process.domain.FileProcessUserGroup;
import com.beiben.work.process.mapper.FileProcessMapper;
import com.beiben.work.process.mapper.FileProcessUserMapper;
import com.beiben.work.process.service.IFileProcessUserService;
import com.beiben.workflow.domain.WfApplyVo;
import com.beiben.workflow.domain.WfCheck;
import com.beiben.workflow.service.IWfApplyService;
import com.beiben.workflow.service.IWfCheckLogService;
import com.github.pagehelper.util.StringUtil;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.exception.BaseException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.sun.xml.bind.v2.TODO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.util.*;

/**
 * 任务分配Service业务层处理
 *
 * @author xgq
 * @date 2020-08-26
 */
@Service
public class FileProcessUserServiceImpl implements IFileProcessUserService {

    @Autowired
    private FileProcessUserMapper fileProcessUserMapper;

    @Autowired
    private FileProcessMapper fileProcessMapper;

    @Autowired
    private IFileService fileService;

    @Autowired
    private ProjectMapper projectMapper;

    @Autowired
    private IWfApplyService wfApplyService;

    @Autowired
    private IWfCheckLogService wfCheckLogService;

    @Autowired
    private IBeiBenUserService beiBenUserService;



    /**
     * 查询任务分配
     *
     * @param itemId 任务分配ID
     * @return 任务分配
     */
    @Override
    public FileProcessUser selectFileProcessUserById(Long itemId) {
        return fileProcessUserMapper.selectFileProcessUserById(itemId);
    }

    /**
     * 查询任务分配列表
     *
     * @param fileProcessUser 任务分配
     * @return 任务分配
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<FileProcessUser> selectFileProcessUserList(FileProcessUser fileProcessUser) throws ParseException {
        if (null == fileProcessUser.getWorkId()) {
            throw new BaseException("请刷新页面后，重试！");
        }
        List<FileProcessUser> fileProcessUsers = fileProcessUserMapper.selectFileProcessUserList(fileProcessUser);
        //验证已完成任务是否超时
        checkProcessUserTimeOut(fileProcessUsers);
        return fileProcessUsers;
    }

    /**
     * 新增任务分配
     *
     * @param fileProcessUser 任务分配
     * @return 结果
     */
    @Override
    public int insertFileProcessUser(FileProcessUser fileProcessUser) {
        // TODO: 2021/1/25 校验节点工作是否已经提交。
        isProjectFinish(fileProcessUser);
        int result = -1;
        Long number = 1l;
        if (null != fileProcessUser.getNumber()) {
            number = fileProcessUser.getNumber();
        }
        fileProcessUser.setCreateBy(SecurityUtils.getUsername());
        for (int i = 0; i < number; i++) {
            fileProcessUser.setCreateTime(DateUtils.getNowDate());
            if (null != fileProcessUser.getUserIds()) {
                for (long userId : fileProcessUser.getUserIds()) {
                    fileProcessUser.setUserId(userId);
                    //检测分任务时间是否在总任务时间段内
                    checkProcessTimeRange(fileProcessUser);
                    setWorkUserGroups(fileProcessUser);//设置分组
                    result = fileProcessUserMapper.insertFileProcessUser(fileProcessUser);
                    insertFileProcessUserGroup(fileProcessUser, 0);//保存分组关系
                }
            } else {
                // TODO: 2022/3/24 根据序号是否为空判断，是否需要查询最大序列编号，自动生成编号
                if(StringUtils.isNotEmpty(fileProcessUser.getSerial())&&"1".equals(fileProcessUser.getIsSerial())){
                    List<FileProcessUser> list = fileProcessUserMapper.selectProjectWorkSerials(fileProcessUser.getWorkId());
                    if(list.size()>0){
                        TreeSet<FileProcessUser> stringComparator = new TreeSet<>(new SortComparator());
                        // 数据排序
                        stringComparator.addAll(list);
                        // 将排序完成的数据放回原集合
                        list.clear();
                        list.addAll(stringComparator);
                        // TODO: 2022/3/24 获取最大序号
                        String serialStart = list.get(list.size()-1).getSerial();
                        String[] listSerial = serialStart.split("\\.");
                        String str = listSerial[listSerial.length-1];
                        Long lStr = Long.valueOf(str) + 1;
                        String endSerial = "";
                        for(int j = 0; j < listSerial.length-1; j++){
                            if(StringUtils.isEmpty(endSerial)){
                                endSerial = listSerial[j];
                            }else {
                                endSerial = endSerial+"."+listSerial[j];
                            }
                        }
                        endSerial = endSerial+"."+lStr;
                        fileProcessUser.setSerial(endSerial);
                    }
                }
                checkProcessTimeRange(fileProcessUser);
                result = fileProcessUserMapper.insertFileProcessUser(fileProcessUser);
                insertFileProcessUserGroup(fileProcessUser, 0);//保存分组关系
            }
        }
        return result;
    }
    /*
    * 校验 节点是否已经提交审核
    * */
    public void isProjectFinish(FileProcessUser fileProcessUser){
        if(GlobalConstant.PROJECT_WORK.equals(fileProcessUser.getWorkType())){
            // TODO: 2021/1/25 查询节点工作状态是否已提交，已提交不能添加工作。
            Project project = projectMapper.selectProjectById(fileProcessUser.getWorkId());
            if(0!=project.getState()){
                throw  new BaseException("已提交的节点下不能新增工作。");
            }
        }
    }

    public FileProcessUser setWorkUserGroups(FileProcessUser fileProcessUser) {
        if (null != fileProcessUser.getGroups()) {
            String[] groups = fileProcessUser.getGroups();
            String workGroups = "";
            for (String group : groups) {
                if ("".equals(workGroups)) {
                    workGroups = String.valueOf(group);
                } else {
                    workGroups = workGroups + "," + group;
                }
            }
            fileProcessUser.setWorkUserGroup(workGroups);
        }
        return fileProcessUser;
    }

    public void insertFileProcessUserGroup(FileProcessUser fileProcessUser, int type) {
        if (null != fileProcessUser.getGroups()) {
            if (type == 1) {//修改数据先删除
                fileProcessUserMapper.deleteFileProcessUserGroup(fileProcessUser.getItemId());
            }
            String[] groups = fileProcessUser.getGroups();
            for (String group : groups) {
                FileProcessUserGroup fileProcessUserGroup = new FileProcessUserGroup();
                fileProcessUserGroup.setGroupCode(group);
                fileProcessUserGroup.setItemId(fileProcessUser.getItemId());
                fileProcessUserMapper.insertFileProcessUserGroup(fileProcessUserGroup);
            }
        }
    }

    /**
     * 修改任务分配
     *
     * @param fileProcessUser 任务分配
     * @return 结果
     */
    @Override
    @Transactional
    public int updateFileProcessUser(FileProcessUser fileProcessUser) {
        if(GlobalConstant.PROJECT_WORK.equals(fileProcessUser.getWorkType())){
            FileProcessUser fpu = fileProcessUserMapper.selectFileProcessUserById(fileProcessUser.getItemId());
            if(0!=fpu.getState()){
                throw new BaseException("已提交审核禁止修改！");
            }else{
                if(DateUtil.getDateMinus(DateUtil.getNowDate(),fileProcessUser.getFinishTime())>0){
                    fileProcessUser.setIsTimeOut("Y");
                }else{
                    fileProcessUser.setIsTimeOut("N");
                }
                return fileProcessUserMapper.updateFileProcessUser(fileProcessUser);
            }
        }else{
            fileProcessUser.setState(0);
            deleteFileProcessUserById(fileProcessUser.getItemId());
            fileProcessUser.setItemId(null);
            FileProcess fileProcess = new FileProcess();
            fileProcess.setWorkId(fileProcessUser.getWorkId());
            fileProcess.setState(0);
            fileProcess.setIsTimeOut("N");
            fileProcessMapper.updateFileProcess(fileProcess);
            return insertFileProcessUser(fileProcessUser);
        }
    }

    /*
     * 根据工作ID修改分派明细
     * */
    @Override
    public int updateFileProcessUserByWorkId(FileProcessUser fileProcessUser) {
        return fileProcessUserMapper.updateFileProcessUserByWorkId(fileProcessUser);
    }

    /**
     * 判断任务是否在总任务
     *
     * @param fileProcessUser
     */
    private void checkProcessTimeRange(FileProcessUser fileProcessUser) {
        Date startTime = null;
        Date finshTime = null;
        if (fileProcessUser.getStartTime().after(fileProcessUser.getFinishTime())) {
            throw new BaseException("开始时间和结束时间不合规！");
        }
        BeiBenUser user = beiBenUserService.selectUserById(fileProcessUser.getUserId());
        // TODO: 2020/12/16 区分日常工作还是项目工作
        if (GlobalConstant.EVERY_DAY_WORK.equals(fileProcessUser.getWorkType())) {
            FileProcess fileProcess = fileProcessMapper.selectFileProcessById(fileProcessUser.getWorkId());
            startTime = fileProcess.getStartTime();
            finshTime = fileProcess.getFinishTime();
            fileProcessUser.setIsSubmitFile(fileProcess.getIsSubmitFile());
            fileProcessUser.setSubmitName(fileProcess.getSubmitName());
            fileProcessUser.setWorkContent(fileProcess.getWorkContent());
            fileProcessUser.setDeptId(user.getDeptId());
            fileProcessUser.setCheckUserId(fileProcess.getUserId());
        } else if (GlobalConstant.PROJECT_WORK.equals(fileProcessUser.getWorkType())) {
            Project project = projectMapper.selectProjectById(fileProcessUser.getWorkId());
            startTime = project.getStartTime();
            finshTime = project.getFinishTime();
//            fileProcessUser.setCheckUserId(project.getCheckUserId());
            fileProcessUser.setDeptId(user.getDeptId());
        } else if (GlobalConstant.PROJECT_NODE.equals(fileProcessUser.getWorkType())) {
            Project project = projectMapper.selectProjectById(fileProcessUser.getParentId());
            startTime = project.getStartTime();
            finshTime = project.getFinishTime();
            fileProcessUser.setCheckUserId(project.getCheckUserId());
            fileProcessUser.setDeptId(user.getDeptId());
        } else {
            throw new BaseException("无法识别工作类型,请确认工作类型！");
        }
        if (fileProcessUser.getStartTime().before(startTime) || fileProcessUser.getStartTime().after(finshTime)) {
            throw new BaseException("任务分配时间超出总任务时间范围,重新选择时间。");
        }
    }

    /**
     * 批量删除任务分配
     *
     * @param itemIds 需要删除的任务分配ID
     * @return 结果
     */
    @Override
    public int deleteFileProcessUserByIds(Long[] itemIds) {
        isState(itemIds);
        // TODO: 2021/2/8  删申请、删审核、删分组

        fileProcessUserMapper.deleteFileProcessUserGroupByItemIds(itemIds);
        return fileProcessUserMapper.deleteFileProcessUserByIds(itemIds);
    }

    /**
     * 删除任务分配信息
     *
     * @param itemId 任务分配ID
     * @return 结果
     */
    @Override
    public int deleteFileProcessUserById(Long itemId) {
        fileProcessUserMapper.deleteFileProcessUserGroup(itemId);
        return fileProcessUserMapper.deleteFileProcessUserById(itemId);
    }

    /*
    * 判断是否已提交审核
    * */
    public void isState(Long[] itemIds){
        String sb ="";
        List<FileProcessUser> fileProcessUsers = fileProcessUserMapper.selectFileProcessUserByIds(itemIds);
        for(FileProcessUser fu:fileProcessUsers){
            if(GlobalConstant.PROJECT_WORK.equals(fu.getWorkType())&&5==fu.getState()){
                sb+="工作："+fu.getWorkContent()+".";
            }
        }
        if(StringUtil.isNotEmpty(sb)){
            sb+="已审核，不能删除。";
            throw  new BaseException(sb);
        }
    }


    /**
     * 批量审批（完成）任务分配
     *
     * @param fileProcessUser
     * @return 结果
     */
    /**
     * @param itemIds
     * @param realFinishTime
     * @return
     */
    @Override
    public int finishedFileProcessUserByIds(Long[] itemIds, Date realFinishTime, Long workId) {
        //TODO 权限管理 只有总任务的创建人才可以完成
        //查询是否输出文件 和 上传文件
        this.verifyAttachment(itemIds);
        List<FileProcessUser> fileProcessUsers = fileProcessUserMapper.selectFileProcessUserByIds(itemIds);
        for (FileProcessUser fileProcessUser : fileProcessUsers) {
            // 验证 超时任务 实际完成时间 是否在 任务完成时间之后
            if ("Y".equals(fileProcessUser.getIsTimeOut()) && fileProcessUser.getFinishTime().after(realFinishTime)) {
                throw new BaseException("超时任务,实际完成时间在完成时间之前,请重新选择完成时间");
            } else if (fileProcessUser.getStartTime().after(realFinishTime)) {
                throw new BaseException("实际完成时间小于任务计划开始时间,请重新选择完成时间");
            }
        }
        //验证任务是否超时
        try {
            checkProcessUserTimeOut(fileProcessUsers);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        //完成任务 修改完成状态，实际完成时间
        int i = fileProcessUserMapper.finishedFileProcessUserByIds(itemIds, realFinishTime, "5");
        for (Long itemId : itemIds) {
            //关联 我的审核 完成审核
            //查询审批信息
            wfCheckLogService.approve(itemId, GlobalConstant.WORK_FILE_PROCESS_USER);
        }
        //判断所有分任务是否完成
        this.confirmProcessIsFinished(workId, realFinishTime);

        return i;
    }

    @Override
    public void verifyAttachment(Long[] itemIds) {
        List<Map<String, Object>> whetherSubmitFile = fileProcessUserMapper.whetherSubmitFile(itemIds);
        //验证是否存在未上传见证性材料的分任务
        boolean submitFileFlag = false;
        StringBuilder isNotSubmitFileUser = new StringBuilder("以下人员未上传见证性材料：");
        for (Map<String, Object> map : whetherSubmitFile) {
            submitFileFlag = true;
            String userName = map.get("userName").toString();
            isNotSubmitFileUser.append(userName + "  ");
        }
        if (submitFileFlag) {
            throw new BaseException(isNotSubmitFileUser.toString());
        }
    }

    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<FileProcessUser> selectFileProcessUserPeerByWorkId(FileProcessUser fileProcessUser) {
        return fileProcessUserMapper.selectFileProcessUserPeerByWorkId(fileProcessUser);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, timeout = 72000, rollbackFor = Exception.class)
    public int changeStatesByIds(Long[] itemIds, String state) {
        Date realFinishTime = null;
        //查询是否输出文件 和 上传文件
        verifyAttachment(itemIds);
        Long workId = null;
        if (state.equals("5")) {
            realFinishTime = DateUtil.dateTime(DateUtil.YYYY_MM_DD, DateUtil.getDate());
            List<FileProcessUser> fileProcessUsers = fileProcessUserMapper.selectFileProcessUserByIds(itemIds);
            for (FileProcessUser fileProcessUser : fileProcessUsers) {
                workId = fileProcessUser.getWorkId();
                // 验证 超时任务完成时间 是否在 任务开始 时间之前
                if (fileProcessUser.getStartTime().after(realFinishTime)) {
                    throw new BaseException("实际完成时间 小于 任务计划开始时间,请重新选择完成时间");
                }
//                if(fileProcessUser.getState()!=1){
//                    throw new BaseException("不能完成未提交审核的任务");
//                }
            }
        }

        // 添加 我的申请 我的审核
        if ("1".equals(state)) {
            WfApplyVo wfApply = new WfApplyVo();
            //任务分配
            wfApply.setApplyType("0");
            for (Long itemId : itemIds) {
                // 查询任务分配详情
                FileProcessUser fileProcessUser = fileProcessUserMapper.selectFileProcessUserById(itemId);
                // 我的申请  申请人
                wfApply.setApplyUserId(fileProcessUser.getUserId());
                List<WfCheck> checks = new ArrayList<>();
                WfCheck wfCheck = new WfCheck();
                wfCheck.setCheckUserId(fileProcessUser.getCheckUserId());
                checks.add(wfCheck);
                wfApply.setChecks(checks);
                wfApply.setRemark(fileProcessUser.getWorkContent());
                wfApply.setTableId(itemId);
                wfApplyService.submitApplyCheck(wfApply);
            }
        }

        int result = fileProcessUserMapper.finishedFileProcessUserByIds(itemIds, realFinishTime, state);
        if (state.equals("5")) {
            for (Long itemId : itemIds) {
                //关联 我的审核 完成审核
                //查询审批信息
                wfCheckLogService.approve(itemId, GlobalConstant.WORK_FILE_PROCESS_USER);
            }
            //判断所有分任务是否完成
            this.confirmProcessIsFinished(workId, realFinishTime);
        }

        return result;
    }

    @Override
    public List<File> selectFiles(Long itemId) {
        File file = new File();
        file.setTableId(itemId);
        file.setTableName(GlobalConstant.WORK_FILE_PROCESS_USER);
        return fileService.selectFileList(file);
    }

    @Override
    public Map<String, List<File>> selectAllFiles(Long itemId) {
        FileProcessUser fileProcessUser = selectFileProcessUserById(itemId);
        if (fileProcessUser == null) {
            throw new BaseException("无该工作信息！");
        }
        // 当前待办工作 表名
        String fileTableName;
        // 相关工作 表名
        String relevantTableName;
        // 相关工作 id
        Long relevantFileId;
        //当前待办工作 类型
        String workType = fileProcessUser.getWorkType();
        //当前待办工作 任务id
        Long workId = fileProcessUser.getWorkId();
        //当前待办工作 id
        Long FileId = fileProcessUser.getItemId();
        if ("0".equals(workType)) {
            //类型为0：日常工作
            // 待办工作对应表名
            fileTableName = GlobalConstant.WORK_FILE_PROCESS_USER;
            //相关工作对应表名
            relevantTableName = GlobalConstant.WORK_FILE_PROCESS;
            //相关工作 及 workId
            relevantFileId = workId;
        } else if ("1".equals(workType) || "2".equals(workType)) {
            //类型为1：项目工作
            //待办项目工作 对应表名
            fileTableName = GlobalConstant.WORK_FILE_PROCESS_USER;
            //查询项目工作相关工作表名
            relevantTableName = GlobalConstant.PM_PROJECT;
            //待办项目工作 对应 相关工作id
            relevantFileId = workId;
            //待办项目工作id
        } else {
            throw new BaseException("无该工作类型信息，无法查询附件！");
        }
        File itemFile = new File();
        itemFile.setTableId(FileId);
        itemFile.setTableName(fileTableName);
        File relevantFile = new File();
        relevantFile.setTableId(relevantFileId);
        relevantFile.setTableName(relevantTableName);
        List<File> itemFiles = fileService.selectFileList(itemFile);
        List<File> relevantFiles = fileService.selectFileList(relevantFile);
        HashMap<String, List<File>> result = new HashMap<>();
        result.put("itemFile", itemFiles);
        result.put("relevantFile", relevantFiles);
        return result;
    }

    @Override
    public int deleteFileProcessByWorkIds(Long[] workIds) {
        List<FileProcessUser> list = fileProcessUserMapper.selectFileProcessUserByWorkIds(workIds);
        for (FileProcessUser pu : list) {
            fileProcessUserMapper.deleteFileProcessUserGroup(pu.getItemId());
        }
        return fileProcessUserMapper.deleteFileProcessByWorkIds(workIds);
    }

    @Override
    public int deleteFileProcessByWorkId(Long workId) {
        List<FileProcessUser> list = fileProcessUserMapper.selectFileProcessUserListByWorkId(workId);
        for (FileProcessUser pu : list) {
            fileProcessUserMapper.deleteFileProcessUserGroup(pu.getItemId());
        }
        return fileProcessUserMapper.deleteFileProcessByWorkId(workId);
    }

    /**
     * 根据itemid查询所属组别
     *
     * @param itemId 数据ID
     * @return 结果
     */
    @Override
    public List<String> selectFileProcessGroupByItemId(Long itemId) {
        return fileProcessUserMapper.selectFileProcessGroupByItemId(itemId);
    }


    private void confirmProcessIsFinished(Long workId, Date realFinishTime) {
        // 查询正在未完成(state!=5)的分任务数量
        int count = fileProcessUserMapper.getFileProcessUserIsNotFinished(workId);
        if (count == 0) {
            // 完成任务 修改完成状态，时间完成时间
            int state = fileProcessMapper.finishedFileProcessById(workId, realFinishTime);
            if (state == 0) {
                throw new BaseException("关联总任务完成失败！");
            }
        }
    }


    /**
     * 判断任务是否超时
     *
     * @param fileProcessUserList
     */
    private void checkProcessUserTimeOut(List<FileProcessUser> fileProcessUserList) throws ParseException {
        // 超时子任务 ItemId 集合
        List<Long> timeOutFIleProcessUserIds = new ArrayList<>();
        // 循环子任务
        for (FileProcessUser fileProcessUser : fileProcessUserList) {
            // 判断任务是否完成  ？？？？？？？
            //TODO  该方法是否成功执行
            if ("5".equals(fileProcessUser.getState())) {
                //任务完成 不做超时处理
                continue;
            }
            // 判断总任务是否超时
            if ("Y".equals(fileProcessUser.getIsTimeOut())) {
                // 任务超时 不重新做超时验证
                continue;
            }
            //判断任务是否超时->当前时间超出完成时间 还未完成的任务
//            if (fileProcessUser.getFinishTime().before(DateUtils.parseDate(DateUtils.getDate(), DateUtils.YYYY_MM_DD))) {
//                timeOutFIleProcessUserIds.add(fileProcessUser.getItemId());
//            }
            // 注释增加  完成时间不为null  时间完成时间大于 规定完成时间的
            if (null != fileProcessUser.getRealFinishTime()) {
                if (DateUtil.getDateMinus(fileProcessUser.getFinishTime(), fileProcessUser.getRealFinishTime()) < 0) {
                    timeOutFIleProcessUserIds.add(fileProcessUser.getItemId());
                }
            }
        }
        if (timeOutFIleProcessUserIds.size() > 0) {
            // 修改子任务超时状态
            fileProcessUserMapper.updateFileProcessUserTimeOutById(timeOutFIleProcessUserIds);
        }
    }

    /**
     * 定时任务超时验证
     */
    public void timeoutVerification() {
        List<FileProcessUser> fileProcessUsers = fileProcessUserMapper.selectNoFinshFileProcessUserList();
        for (FileProcessUser fileProcessUser : fileProcessUsers) {
            FileProcessUser fp = new FileProcessUser();
            fp.setIsTimeOut("Y");
            fp.setItemId(fileProcessUser.getItemId());
            fileProcessUserMapper.updateFileProcessUser(fp);

        }
    }

}
